/*
 *  m_webirc.c: Makes CGI:IRC users appear as coming from their real host
 *              ported from ircd-ratbox to ircd-hybrid by ph0x
 *
 *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
 *  Copyright (C) 1996-2002 Hybrid Development Team
 *  Copyright (C) 2002-2006 ircd-ratbox development team
 *  Copyright (C) 2007 FreeQuest IRC Network Coders
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 *  USA
 *
 *  $Id: m_webirc.c 23014 2006-08-31 20:47:45Z androsyn $
 *
 *  I hacked this for hybrid 7.2.3, email questions / comments to
 *  ph0x@freequest.net
 *
 *  NOTE: This compiles, and it seems to work. If you find any bugs
 *        or other odd stuff, please let me know! -ph0x
 *
 *  HOW?: hybrid has some functions that ratbox hasn't got.
 *        the find_address_conf() functions uses the password parsed
 *        from cgiirc, so there is no need to verify that the auth
 *        block has "webirc." as spoof, since we need the password
 *        to get our AccessItem. Don't remove the spoof in config,
 *        else IsConfDoSpoofIp will return false and CGI:IRC wont
 *        work. (yes, this text probably doesnt make sence, it's
 *        just some mental notes from my side -ph0x)
 *        
 *
 */

/* Usage:
 * auth {
 *   user = "webirc@<cgiirc ip>"; # if identd used, put ident username instead
 *   password = "<password>"; # encryption possible
 *   spoof = "webirc."
 *   class = "users";
 * };
 * excempt {
 *   ip = "<cgiirc ip>";
 * };
 * Possible flags:
 *   encrypted - password is encrypted (recommended)
 *   kline_exempt - k/g lines on the cgiirc ip are ignored
 *   gline_exempt - glines on the cgiirc ip are ignored
 * dlines are checked on the cgiirc ip (of course).
 * k/d/g/x lines, auth blocks, user limits, etc are checked using the
 * real host/ip.
 * The password should be specified unencrypted in webirc_password in
 * cgiirc.config
 */

#include "stdinc.h"
#include "handlers.h"
#include "client.h"		/* client struct */
#include "irc_string.h"
#include "sprintf_irc.h"
#include "hostmask.h"
#include "send.h"		/* sendto_one */
#include "numeric.h"		/* ERR_xxx */
#include "ircd.h"		/* me */
#include "msg.h"
#include "parse.h"
#include "modules.h"
#include "s_serv.h"
#include "hash.h"
#include "s_conf.h"

static void mr_webirc(struct Client *, struct Client *, int, char *[]);

static char buf[IRCD_BUFSIZE];
struct Message webirc_msgtab = {
	"WEBIRC", 0, 0, 5, 5, MFLG_SLOW, 0, 
	{ mr_webirc, m_ignore, m_ignore, m_ignore, m_ignore, m_ignore }
};


#ifndef STATIC_MODULES
/* Here we tell it what to do when the module is loaded */
void
_modinit(void)
{
  /* This will add the commands in webirc_msgtab (which is above) */
  mod_add_cmd(&webirc_msgtab);
}

/* here we tell it what to do when the module is unloaded */
void
_moddeinit(void)
{
  /* This will remove the commands in webirc_msgtab (which is above) */
  mod_del_cmd(&webirc_msgtab);
}

/* When we last modified the file (shown in /modlist), this is usually:
 */
const char *_version = "$Revision: 20070415 $";
#endif

/*
 * mr_webirc - webirc message handler
 *      parv[0] = sender prefix
 *      parv[1] = password
 *      parv[2] = fake username (we ignore this)
 *	parv[3] = fake hostname 
 *	parv[4] = fake ip
 */
static void
mr_webirc(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
{
	struct AccessItem *aconf;
	const char *encr;
        char pton[16];

	if (!strchr(parv[4], '.') && !strchr(parv[4], ':'))
	{
		sendto_one(source_p, "NOTICE %s :Invalid IP", me.name);
		return;
	}

	aconf = find_address_conf(client_p->host,
				IsGotId(client_p) ? client_p->username : "webirc",
				(struct irc_ssaddr *) &client_p->localClient->ip,
				client_p->localClient->ip.ss.ss_family, (char *)parv[1]);

	if (aconf == NULL || !(aconf->status & CONF_CLIENT))
		return;

	if (!IsConfDoSpoofIp(aconf))
	{
		/* XXX */
		sendto_one(source_p, "NOTICE * :Not a CGI:IRC auth block");
		return;
	}
	if (EmptyString(aconf->passwd))
	{
		sendto_one(source_p, "NOTICE * :CGI:IRC auth blocks must have a password");
		return;
	}

	/*
	 * This probably isn't necessary, because we are using the password
	 * to get our aconf object, which will exit in !IsConfDoSpoofIp(aconf)
	 * if not correct. I'm not touching this yet. -ph0x
	 */
	if (EmptyString(parv[1]))
		encr = "";
	else if (IsConfEncrypted(aconf))
		encr = crypt(parv[1], aconf->passwd);
	else
		encr = parv[1];

	if (strcmp(encr, aconf->passwd))
	{
		sendto_one(source_p, "NOTICE * :CGI:IRC password incorrect");
		return;
	}

	/* rest would be necessary */

	strlcpy(source_p->sockhost, parv[4], sizeof(source_p->sockhost));

	if(strlen(parv[3]) <= HOSTLEN)
		strlcpy(source_p->host, parv[3], sizeof(source_p->host));
	else
		strlcpy(source_p->host, source_p->sockhost, sizeof(source_p->host));

        SetIPSpoof(source_p);
        SetVHost(source_p);
	
	/* Check dlines now, k/glines will be checked on registration */
	if((aconf = find_dline_conf((struct irc_ssaddr *)&source_p->localClient->ip, 
			       source_p->localClient->ip.ss.ss_family)))
	{
		if(!(aconf->status & CONF_EXEMPTDLINE))
		{
			exit_client(client_p, &me, "D-lined");
			return;
		}
	}

	sendto_one(source_p, ":%s NOTICE AUTH :*** CGI:IRC host/IP set to %s %s", me.name,  source_p->sockhost, source_p->host);
	return;
}
